import { NextFunction, Request, Response } from "express";
import { PostService, UserService } from "../services";
import { paginate } from "../utils";
import { Like } from "typeorm";
import { RoleUser } from "../entities/user";

export class UserController {
  public static async me(req: Request, res: Response, next: NextFunction) {
    try {
      const user = res.locals.user;
      res.json(user);
    } catch (err) {
      next(err);
    }
  }

  public static async findOne(req: Request, res: Response, next: NextFunction) {
    try {
      const user = await UserService.findByName(req.params.name);
      if (!user) {
        return res.status(404).json({
          status: "fail",
          message: "User not found",
        });
      }
      res.json(user);
    } catch (err) {
      next(err);
    }
  }

  public static async findMany(
    req: Request,
    res: Response,
    next: NextFunction,
  ) {
    try {
      const users = await UserService.find({
        ...paginate(req),
        where: { name: Like(`%${req.query.q || ""}%`) },
      });
      res.json({
        data: users[0],
        total: users[1],
      });
    } catch (err) {
      next(err);
    }
  }

  public static async findPosts(
    req: Request,
    res: Response,
    next: NextFunction,
  ) {
    try {
      const user = await UserService.findByName(req.params.name);
      if (!user) {
        return res.status(404).json({
          status: "fail",
          message: "User not found",
        });
      }
      const posts = await PostService.find({
        ...paginate(req),
        where: [
          {
            title: Like(`%${req.query.q || ""}%`),
            user: {
              id: user.id,
            },
          },
          {
            content: Like(`%${req.query.q || ""}%`),
            user: {
              id: user.id,
            },
          },
        ],
      });
      res.json({ data: posts[0], total: posts[1] });
    } catch (err) {
      next(err);
    }
  }

  public static async update(req: Request, res: Response, next: NextFunction) {
    try {
      const user = await UserService.findByName(req.params.name);
      if (!user) {
        return res.status(404).json({
          status: "fail",
          message: "User not found",
        });
      }
      if (
        res.locals.user.id !== user.id &&
        res.locals.user.role !== RoleUser.ADMIN
      ) {
        return res.status(403).json({
          status: "fail",
          message: "Not allowed",
        });
      }
      await UserService.update(user.name, req.body);
      res.sendStatus(200);
    } catch (err) {
      next(err);
    }
  }

  public static async remove(req: Request, res: Response, next: NextFunction) {
    try {
      const user = await UserService.findByName(req.params.name);
      if (!user) {
        return res.status(404).json({
          status: "fail",
          message: "User not found",
        });
      }
      if (
        res.locals.user.id !== user.id &&
        res.locals.user.role !== RoleUser.ADMIN
      ) {
        return res.status(403).json({
          status: "fail",
          message: "Not allowed",
        });
      }
      await UserService.remove(user);
      res.sendStatus(200);
    } catch (err) {
      next(err);
    }
  }
}
